﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace MyGIS
{
    public class GISShapefile
    {
        [StructLayout(LayoutKind.Sequential, Pack = 4)]//严格按照定义的字节顺序和字节数存储数据，layout：布局
        struct ShapefileHeader//文件头结构
        {
            public int Unused1, Unused2, Unused3, Unused4;
            public int Unused5, Unused6, Unused7, Unused8;
            public int ShapeType;
            public double Xmin, Ymin, Xmax, Ymax;
            public double Unused9, Unused10, Unused11, Unused12;
        }

        ShapefileHeader ReadFileHeader(BinaryReader br)//读取文件头
        {
            byte[] buff = br.ReadBytes(Marshal.SizeOf(typeof(ShapefileHeader)));//将与ShapefileHeader同样大小的字节赋给buff字符串
            GCHandle handle = GCHandle.Alloc(buff, GCHandleType.Pinned);//handle获取buff数组在内存中的指针
            ShapefileHeader header = (ShapefileHeader)Marshal.PtrToStructure
                (handle.AddrOfPinnedObject(), typeof(ShapefileHeader));//该指针指向的内存被映射给ShapefileHeader结构体的实例header
            handle.Free();//释放handle
            return header;
        }

        public GISLayer ReadShapefile(string shpfilename)//读取Shapefile文件
        {
            FileStream fsr = new FileStream(shpfilename, FileMode.Open);
            BinaryReader br = new BinaryReader(fsr);
            ShapefileHeader sfh = ReadFileHeader(br);
            SHAPETYPE ShapeType = (SHAPETYPE)Enum.Parse(
                typeof(SHAPETYPE), sfh.ShapeType.ToString());//读取ShapeType
            GISExtent extent = new GISExtent(new GISVertex(sfh.Xmin, sfh.Ymin), new GISVertex(sfh.Xmax, sfh.Ymax));//读取地图范围
            GISLayer layer = new GISLayer(shpfilename, ShapeType, extent);//创建图层
            while (br.PeekChar() != -1)//当未读到文件末端时执行
            {
                RecordHeader rh = ReadRecordHeader(br);
                int RecordLength = FromBigToLittle(rh.RecordLength) * 2 - 4;
                byte[] RecordContent = br.ReadBytes(RecordLength);
                if (ShapeType == SHAPETYPE.point)//若判断为点实体
                {
                    GISPoint onepoint = ReadPoint(RecordContent);
                    GISFeature onefeature = new GISFeature(onepoint, new GISAttribute());
                    layer.AddFeature(onefeature);
                }
            }
            br.Close();
            fsr.Close();
            return layer;
        }

        GISPoint ReadPoint(byte[] RecordContent)
        {
            double x = BitConverter.ToDouble(RecordContent, 0);
            double y = BitConverter.ToDouble(RecordContent, 8);
            return new GISPoint(new GISVertex(x, y));
        }


        /// <summary>
        /// 具有相同类型空间实体的集合（图层）
        /// </summary>
        public enum SHAPETYPE//记录shapefile中存储的空间对象类型
        {
            point = 1,
            line = 3,
            poloygon = 5
        }


        [StructLayout(LayoutKind.Sequential, Pack = 4)]//记录头的结构体
        struct RecordHeader
        {
            public int RecordNumber;
            public int RecordLength;
            public int ShapeType;
        }
        RecordHeader ReadRecordHeader(BinaryReader br)//读记录头
        {
            byte[] buff = br.ReadBytes(Marshal.SizeOf(typeof(RecordHeader)));
            GCHandle handle = GCHandle.Alloc(buff, GCHandleType.Pinned);
            RecordHeader header = (RecordHeader)Marshal.PtrToStructure
                (handle.AddrOfPinnedObject(), typeof(RecordHeader));
            handle.Free();
            return header;
        }

        int FromBigToLittle(int bigvalue)
        {
            byte[] bigbytes = new byte[4];
            GCHandle handle = GCHandle.Alloc(bigbytes, GCHandleType.Pinned);
            Marshal.StructureToPtr(bigvalue, handle.AddrOfPinnedObject(), false);
            handle.Free();
            byte b2 = bigbytes[2];
            byte b3 = bigbytes[3];
            bigbytes[3] = bigbytes[0];
            bigbytes[2] = bigbytes[1];
            bigbytes[1] = b2;
            bigbytes[0] = b3;
            return BitConverter.ToInt32(bigbytes, 0);
        }
    }

     public class GISLayer
    {
        public string Name;//图层名称
        public GISExtent Extent;//地图范围
        public bool DrawAttributeOrNot;//绘制图层时是否标注属性信息
        public int LabelIndex;//需要标注的属性序列号
        public GISShapefile.SHAPETYPE ShapeType;//空间对象类型
        List<GISFeature> Features = new List<GISFeature>();//用于记录该图层中包含的所有空间对象实体
        public GISLayer(string _name, GISShapefile.SHAPETYPE _shapetype, GISExtent _extent)
        {
            Name = _name;
            ShapeType = _shapetype;
            Extent = _extent;
        }
        public void draw(Graphics graphics, GISView view)//绘制空间实体
        {
            for (int i = 0; i < Features.Count; i++)
            {
                Features[i].draw(graphics, view, DrawAttributeOrNot, LabelIndex);
            }
        }
        public void AddFeature(GISFeature feature)//向图层中添加要素
        {
            Features.Add(feature);
        }
        public int FeatureCount()//用于获取Feature中元素的数量
        {
            return Features.Count;
        }
    }
}
